/*
 * Image.java
 *
 * Created on October 11, 2009, 12:12 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package com.nextel.util.lwuit;


//import java.lang.ref.WeakReference;
 //import java.util.Hashtable;

/**
 * Abstracts the underlying platform images allowing us to treat them as a uniform
 * object.
 * 
 * @author Chen Fishbein
 */
public class Image {
//    private WeakReference rgbCache;
    private javax.microedition.lcdui.Image image;   
    
    /** Creates a new instance of ImageImpl */
    Image(javax.microedition.lcdui.Image image) {
        this.image = image;
    }

    /** Creates a new instance of ImageImpl */
    Image(int[] imageArray, int w, int h) {
        //this(Display.getInstance().getImplementation().createImage(imageArray, w, h));
        this(javax.microedition.lcdui.Image.createRGBImage(imageArray, w, h, true));
    }

    
//    private Hashtable getScaleCache() {
//        if(scaleCache == null) {
//            Hashtable h = new Hashtable();
//            scaleCache = new WeakReference(h);
//            return h;
//        }
//        Hashtable h = (Hashtable)scaleCache.get();
//        if(h == null) {
//            h = new Hashtable();
//            scaleCache = new WeakReference(h);
//        }
//        return h;
//    }


    void setImage(javax.microedition.lcdui.Image image) {
        this.image = image;
    }

 
    /**
     * creates an image from an RGB image
     * 
     * @param rgb the RGB image array data
     * @param width the image width
     * @param height the image height
     * @return an image from an RGB image
     */
    public static Image createImage(int[] rgb, int width, int height) {
        try {
            //Image i = new Image(Display.getInstance().getImplementation().createImage(rgb, width, height));
            //return i;
            return new Image(javax.microedition.lcdui.Image.createRGBImage(rgb, width, height, true));
        } catch(OutOfMemoryError err) {
            // Images have a major bug on many phones where they sometimes throw 
            // an OOM with no reason. A system.gc followed by the same call over
            // solves the problem. This has something to do with the fact that 
            // there is no Image.dispose method in existance.
            err.printStackTrace();
            
           System.gc();System.gc();
            //return new Image(Display.getInstance().getImplementation().createImage(rgb, width, height));
            return new Image(javax.microedition.lcdui.Image.createRGBImage(rgb, width, height, true));
        }
    }


    
    /**
     * creates an image from a given byte array data
     * 
     * @param bytes the array of image data in a supported image format
     * @param offset the offset of the start of the data in the array
     * @param len the length of the data in the array
     * @return the newly created image
     */
    public static Image createImage(byte[] bytes,int offset,int len) {
        try {
            return new Image(javax.microedition.lcdui.Image.createImage(bytes, offset, len));
           // return new Image(Display.getInstance().getImplementation().createImage(bytes, offset, len));
        } catch(OutOfMemoryError err) {
            // Images have a major bug on many phones where they sometimes throw 
            // an OOM with no reason. A system.gc followed by the same call over
            // solves the problem. This has something to do with the fact that 
            // there is no Image.dispose method in existance.

            
            System.gc();System.gc();

            return new Image(javax.microedition.lcdui.Image.createImage(bytes, offset, len));
           // return new Image(Display.getInstance().getImplementation().createImage(bytes, offset, len));
        }
    }

    /**
     * If this is a mutable image a graphics object allowing us to draw on it
     * is returned.
     * 
     * @return Graphics object allowing us to manipulate the content of a mutable image
     */
    public Graphics getGraphics() {
        //return new Graphics(Display.getInstance().getImplementation().getNativeGraphics(image));
        return new Graphics(((javax.microedition.lcdui.Image) image).getGraphics());
    }
    
    /**
     * Returns the width of the image
     * 
     * @return the width of the image
     */
    public int getWidth() {
        //return Display.getInstance().getImplementation().getImageWidth(image);
        return ((javax.microedition.lcdui.Image) image).getWidth();
    }
    
    /**
     * Returns the height of the image
     * 
     * @return the height of the image
     */
    public int getHeight() {
        return ((javax.microedition.lcdui.Image) image).getHeight();
    }

    /**
     * Callback invoked internally by LWUIT to draw the image/frame onto the display.
     * Image subclasses can override this method to perform drawing of custom image types.
     *
     * @param g the graphics object
     * @param nativeGraphics the underlying native graphics which might be essential for some image types
     * @param x the x coordinate
     * @param y the y coordinate
     */
    protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) {
        //g.drawImage(image, x, y, transform);
        g.drawImage((javax.microedition.lcdui.Image)image, x, y);
    }
    
    /**
     * Obtains ARGB pixel data from the specified region of this image and 
     * stores it in the provided array of integers. Each pixel value is 
     * stored in 0xAARRGGBB format, where the high-order byte contains the 
     * alpha channel and the remaining bytes contain color components for red, 
     * green and blue, respectively. The alpha channel specifies the opacity of 
     * the pixel, where a value of 0x00  represents a pixel that is fully 
     * transparent and a value of 0xFF  represents a fully opaque pixel. 
     * The rgb information contained within the image, this method ignors 
     * rotation and mirroring in some/most situations and cannot be 
     * used in such cases.
     * 
     * @param rgbData an array of integers in which the ARGB pixel data is 
     * stored
     * @param offset the index into the array where the first ARGB value is 
     * stored
     * @param scanlength the relative offset in the array between 
     * corresponding pixels in consecutive rows of the region
     * @param x the x-coordinate of the upper left corner of the region
     * @param y the y-coordinate of the upper left corner of the region
     * @param width the width of the region
     * @param height the height of the region
     */
    void getRGB(int[] rgbData,
            int offset,
            int x,
            int y,
            int width,
            int height){
        ((javax.microedition.lcdui.Image) image).getRGB(rgbData, offset, width, x, y, width, height);
    }
    
    
    /**
     * Returns the content of this image as a newly created ARGB array.
     * 
     * @return new array instance containing the ARGB data within this image
     */
    public int[] getRGB() {
        return getRGBImpl();
    }

    /**
     * Returns the content of this image as a newly created ARGB array or a cached
     * instance if possible. Note that cached instances may be garbage collected.
     *
     * @return array instance containing the ARGB data within this image
     */
//    public int[] getRGBCached() {
//        int[] r = getRGBCache();
//        if(r == null) {
//            r = getRGBImpl();
//            rgbCache = new WeakReference(r);
//        }
//        return r;
//    }

//    int[] getRGBCache() {
//        if(rgbCache != null) {
//            int[] rgb = (int[])rgbCache.get();
//            return rgb;
//        }
//        return null;
//    }
    
    int[] getRGBImpl() {
        int width = getWidth();
        int height = getHeight();
        int[] rgbData = new int[width * height];
        getRGB(rgbData, 0, 0, 0, width, height);
        return rgbData;
    }
    
    /**
     * Returns true if this is an animated image
     * 
     * @return true if this image represents an animation
     */
//    public boolean isAnimation() {
//        return animated;
//    }
    void clear(){
        this.image = null;
//        if(this.rgbCache != null)this.rgbCache.clear();
//        this.rgbCache = null;
        System.gc();
    }

}
